package cn.wolfcode.luowowo.service.impl;

import cn.wolfcode.luowowo.cache.service.IUserInfoRedisService;
import cn.wolfcode.luowowo.domain.Destination;
import cn.wolfcode.luowowo.domain.Travel;
import cn.wolfcode.luowowo.domain.UserInfo;
import cn.wolfcode.luowowo.query.SearchQueryObject;
import cn.wolfcode.luowowo.query.TravelQuery;
import cn.wolfcode.luowowo.repository.TravelRepository;
import cn.wolfcode.luowowo.service.IDestinationService;
import cn.wolfcode.luowowo.service.ITravelService;
import cn.wolfcode.luowowo.service.IUserInfoService;
import cn.wolfcode.luowowo.util.DBHelper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;

import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.Date;
import java.util.List;

@Service
public class TravelServiceImpl implements ITravelService {
    @Autowired
    private TravelRepository travelRepository;

    @Autowired
    private MongoTemplate mongoTemplate;

    @Autowired
    private IUserInfoService userInfoService;

    @Autowired
    private IUserInfoRedisService userInfoRedisService;

    @Autowired
    private IDestinationService destinationService;

    @Override
    public String insert(Travel travel, String token) {
        travel.setId(null);
        UserInfo user = userInfoRedisService.getUserByToken(token);
        travel.setUserId(user.getId());
        Destination dest = destinationService.select(travel.getDestId());
        travel.setDestName(dest.getName());
        travel.setCreateTime(new Date());
        travel.setLastUpdateTime(new Date());
        travelRepository.save(travel);
        return travel.getId();
    }

    @Override
    public void update(Travel travel) {
        Query query = new Query();
        DBHelper.update(mongoTemplate, query, travel, "destId", "title", "summary", "coverUrl"
                , "travelTime", "perExpend", "day", "person");
        Travel travel1 = travelRepository.findById(travel.getId()).get();
        Destination dest = destinationService.select(travel.getDestId());
        travel1.setDestName(dest.getName());
        travel1.setLastUpdateTime(new Date());
        travelRepository.save(travel);
    }

    @Override
    public void delete(String id) {
        travelRepository.deleteById(id);
    }

    @Override
    public Travel select(String id) {
        Travel travel = travelRepository.findById(id).get();
        UserInfo user = userInfoService.get(travel.getUserId());
        travel.setAuthor(user);
        Destination destination = destinationService.select(travel.getDestId());
        travel.setDest(destination);
        return travel;
    }

    @Override
    public Page<Travel> query(TravelQuery qo) {
        Query query = new Query();
        if (qo.getState() != null && qo.getState() != -1) {
            query.addCriteria(Criteria.where("state").is(qo.getState()));
        }
        PageRequest pageable = PageRequest.of(qo.getCurrentPage() - 1, qo.getPageSize()
                , Sort.Direction.ASC, "_id");

        Page<Travel> page = DBHelper.query(mongoTemplate, Travel.class, query, pageable);
        for (Travel travel : page.getContent()) {
            UserInfo user = userInfoService.get(travel.getUserId());
            travel.setAuthor(user);
        }
        return page;
    }

    @Override
    public void changeState(String id, int state) {
        Travel travel = this.select(id);
        if (travel != null && travel.getState() == Travel.STATE_WAITING) {
            if (state == Travel.STATE_RELEASE) {
                travel.setState(state);
                travel.setReleaseTime(new Date());
                travel.setLastUpdateTime(new Date());
                travelRepository.save(travel);
            }
            if (state == Travel.STATE_REJECT) {
                travel.setState(state);
                travel.setLastUpdateTime(new Date());
                travelRepository.save(travel);
            }
        } else if (travel != null && travel.getState() == Travel.STATE_RELEASE) {
            if (state == Travel.STATE_WAITING) {
                travel.setState(state);
                travel.setLastUpdateTime(new Date());
                travelRepository.save(travel);
            }
        }
    }

    @Override
    public String getContentById(String id) {
        Travel travel = travelRepository.findById(id).get();
        return travel.getContent();
    }

    @Override
    public List<Travel> listAll() {
        return travelRepository.findAll();
    }

    @Override
    public Page<Travel> queryOrderByViewnum(TravelQuery qo) {
        Query query = new Query();

        query.addCriteria(Criteria.where("state").is(Travel.STATE_RELEASE));

        if (StringUtils.hasLength(qo.getDestId())) {
            query.addCriteria(Criteria.where("destId").is(qo.getDayType()));
        }

        if (qo.getOrderType() != null && qo.getOrderType() == 2) {
            query.with(Sort.by(Sort.Direction.DESC, "viewnum"));
        } else {
            query.with(Sort.by(Sort.Direction.DESC, "createTime"));
        }

        Criteria criteria = new Criteria();

        if (qo.getPerExpendType() != null && qo.getPerExpendType() != -1 && qo.getDayType() != null && qo.getDayType() != -1) {
            if (qo.getPerExpendType() == 1) {
                if (qo.getDayType() == 1) {
                    criteria.andOperator(
                            Criteria.where("day").lte(3),
                            Criteria.where("perExpend").lte(999)
                    );
                } else if (qo.getDayType() == 2) {
                    criteria.andOperator(
                            Criteria.where("day").gte(4),
                            Criteria.where("day").lte(7),
                            Criteria.where("perExpend").lte(999)
                    );
                } else if (qo.getDayType() == 3) {
                    criteria.andOperator(
                            Criteria.where("day").gte(8),
                            Criteria.where("day").lte(14),
                            Criteria.where("perExpend").lte(999)
                    );
                } else if (qo.getDayType() == 4) {
                    criteria.andOperator(
                            Criteria.where("day").gte(15),
                            Criteria.where("perExpend").lte(999)
                    );
                }
            } else if (qo.getPerExpendType() == 2) {
                if (qo.getDayType() == 1) {
                    criteria.andOperator(
                            Criteria.where("day").lte(3),
                            Criteria.where("perExpend").gte(1000),
                            Criteria.where("perExpend").lt(6000)
                    );
                } else if (qo.getDayType() == 2) {
                    criteria.andOperator(
                            Criteria.where("day").gte(4),
                            Criteria.where("day").lte(7),
                            Criteria.where("perExpend").gte(1000),
                            Criteria.where("perExpend").lt(6000)
                    );
                } else if (qo.getDayType() == 3) {
                    criteria.andOperator(
                            Criteria.where("day").gte(8),
                            Criteria.where("day").lte(14),
                            Criteria.where("perExpend").gte(1000),
                            Criteria.where("perExpend").lt(6000)
                    );
                } else if (qo.getDayType() == 4) {
                    criteria.andOperator(
                            Criteria.where("day").gte(15),
                            Criteria.where("perExpend").gte(1000),
                            Criteria.where("perExpend").lt(6000)
                    );
                }
            } else if (qo.getPerExpendType() == 3) {
                if (qo.getDayType() == 1) {
                    criteria.andOperator(
                            Criteria.where("day").lte(3),
                            Criteria.where("perExpend").gte(6000),
                            Criteria.where("perExpend").lt(20000)
                    );
                } else if (qo.getDayType() == 2) {
                    criteria.andOperator(
                            Criteria.where("day").gte(4),
                            Criteria.where("day").lte(7),
                            Criteria.where("perExpend").gte(6000),
                            Criteria.where("perExpend").lt(20000)
                    );
                } else if (qo.getDayType() == 3) {
                    criteria.andOperator(
                            Criteria.where("day").gte(8),
                            Criteria.where("day").lte(14),
                            Criteria.where("perExpend").gte(6000),
                            Criteria.where("perExpend").lt(20000)
                    );
                } else if (qo.getDayType() == 4) {
                    criteria.andOperator(
                            Criteria.where("day").gte(15),
                            Criteria.where("perExpend").gte(6000),
                            Criteria.where("perExpend").lt(20000)
                    );
                }
            } else if (qo.getPerExpendType() == 4) {
                if (qo.getDayType() == 1) {
                    criteria.andOperator(
                            Criteria.where("day").lte(3),
                            Criteria.where("perExpend").lte(999),
                            Criteria.where("perExpend").gte(20000)
                    );
                } else if (qo.getDayType() == 2) {
                    criteria.andOperator(
                            Criteria.where("day").gte(4),
                            Criteria.where("day").lte(7),
                            Criteria.where("perExpend").gte(20000)
                    );
                } else if (qo.getDayType() == 3) {
                    criteria.andOperator(
                            Criteria.where("day").gte(8),
                            Criteria.where("day").lte(14),
                            Criteria.where("perExpend").gte(20000)
                    );
                } else if (qo.getDayType() == 4) {
                    criteria.andOperator(
                            Criteria.where("day").gte(15),
                            Criteria.where("perExpend").gte(20000)
                    );
                }
            }
        } else {
            if (qo.getPerExpendType() != null && qo.getPerExpendType() != -1) {
                if (qo.getPerExpendType() == 1) {
                    criteria.andOperator(
                            Criteria.where("perExpend").lte(999)
                    );
                } else if (qo.getPerExpendType() == 2) {
                    criteria.andOperator(
                            Criteria.where("perExpend").gte(1000),
                            Criteria.where("perExpend").lt(6000)
                    );
                } else if (qo.getPerExpendType() == 3) {
                    criteria.andOperator(
                            Criteria.where("perExpend").gte(6000),
                            Criteria.where("perExpend").lt(20000)
                    );
                } else if (qo.getPerExpendType() == 4) {
                    criteria.andOperator(
                            Criteria.where("perExpend").gte(20000)
                    );
                }
            } else if (qo.getDayType() != null && qo.getDayType() != -1) {
                if (qo.getDayType() == 1) {
                    criteria.andOperator(
                            Criteria.where("day").lte(3)
                    );
                } else if (qo.getDayType() == 2) {
                    criteria.andOperator(
                            Criteria.where("day").gte(4),
                            Criteria.where("day").lte(7)
                    );
                } else if (qo.getDayType() == 3) {
                    criteria.andOperator(
                            Criteria.where("day").gte(8),
                            Criteria.where("day").lte(14)
                    );
                } else if (qo.getDayType() == 4) {
                    criteria.andOperator(
                            Criteria.where("day").gte(15)
                    );
                }
            }
        }

        query.addCriteria(criteria);

        PageRequest pageable = PageRequest.of(qo.getCurrentPage() - 1, qo.getPageSize()
                , Sort.Direction.ASC, "_id");
        Page<Travel> page = DBHelper.query(mongoTemplate, Travel.class, query, pageable);
        for (Travel travel : page.getContent()) {
            UserInfo user = userInfoService.get(travel.getUserId());
            travel.setAuthor(user);
        }
        return page;
    }

    @Override
    public List<Travel> getViewnumTop3(String destId) {
        List<Travel> travels = travelRepository.findByDestIdOrderByViewnumDesc(destId);
        if (travels.size() >= 3) {
            travels.subList(0, 3);
        }
        return travels;
    }

    @Override
    public List<Travel> listByKeyword(SearchQueryObject qo) {
        Query query = new Query();
        Criteria criteria = new Criteria();
        criteria.orOperator(
                Criteria.where("title").regex(".*" + qo.getKeyword() + ".*"),
                Criteria.where("summary").regex(".*" + qo.getKeyword() + ".*")
        );
        query.addCriteria(criteria);
        List<Travel> travels = mongoTemplate.find(query, Travel.class, "travel");
        for (Travel travel : travels) {
            UserInfo user = userInfoService.get(travel.getUserId());
            travel.setAuthor(user);
        }
        return travels;
    }

    @Override
    public Page<Travel> queryByKeyword(SearchQueryObject qo) {
        Query query = new Query();
        query.addCriteria(Criteria.where("state").is(Travel.STATE_RELEASE));
        Criteria criteria = new Criteria();
        criteria.andOperator(
                Criteria.where("title").regex(".*" + qo.getKeyword() + ".*"),
                Criteria.where("summary").regex(".*" + qo.getKeyword() + ".*")
        );
        query.addCriteria(criteria);
        PageRequest pageable = PageRequest.of(qo.getCurrentPage() - 1, 5
                , Sort.Direction.ASC, "_id");
        return DBHelper.query(mongoTemplate, Travel.class, query, pageable);
    }

    @Override
    public void updateVO(Travel t) {
        Query query = new Query();
        query.addCriteria(Criteria.where("_id").is(t.getId()));
        DBHelper.update(mongoTemplate, query, t, "viewnum", "replynum", "favornum"
                , "sharenum", "thumbsupnum");
    }
}
